home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / gedit-2 / plugins / snippets / Manager.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  48.8 KB  |  1,164 lines

  1. #    Gedit snippets plugin
  2. #    Copyright (C) 2005-2006  Jesse van den Kieboom <jesse@icecrew.nl>
  3. #
  4. #    This program is free software; you can redistribute it and/or modify
  5. #    it under the terms of the GNU General Public License as published by
  6. #    the Free Software Foundation; either version 2 of the License, or
  7. #    (at your option) any later version.
  8. #
  9. #    This program is distributed in the hope that it will be useful,
  10. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #    GNU General Public License for more details.
  13. #
  14. #    You should have received a copy of the GNU General Public License
  15. #    along with this program; if not, write to the Free Software
  16. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17.  
  18. import os
  19. import tempfile
  20. import shutil
  21.  
  22. import gobject
  23. import gtk
  24. from gtk import gdk
  25. import gtksourceview2 as gsv
  26. import pango
  27. import gedit
  28. import gio
  29.  
  30. from Snippet import Snippet
  31. from Helper import *
  32. from Library import *
  33. from Importer import *
  34. from Exporter import *
  35. from Document import Document
  36.  
  37. class Manager:
  38.         NAME_COLUMN = 0
  39.         SORT_COLUMN = 1
  40.         OBJ_COLUMN = 2
  41.         TARGET_URI = 105
  42.  
  43.         model = None
  44.         drag_icons = ('gnome-mime-application-x-tarz', 'gnome-package', 'package')
  45.         default_export_name = _('Snippets archive') + '.tar.gz'
  46.         dragging = False
  47.         dnd_target_list = [('text/uri-list', 0, TARGET_URI)]
  48.  
  49.         def __init__(self, datadir):
  50.                 self.datadir = datadir
  51.                 self.snippet = None
  52.                 self.dlg = None
  53.                 self._temp_export = None
  54.                 self.snippets_doc = None
  55.                 self.manager = None
  56.                 self.default_size = None
  57.  
  58.                 self.key_press_id = 0
  59.                 self.tooltips = gtk.Tooltips()
  60.                 self.run()
  61.         
  62.         def get_language_snippets(self, path, name = None):
  63.                 library = Library()
  64.                 
  65.                 name = self.get_language(path)
  66.                 nodes = library.get_snippets(name)
  67.  
  68.                 return nodes
  69.  
  70.         def add_new_snippet_node(self, parent):
  71.                 return self.model.append(parent, ('<i>' + _('Add a new snippet...') + \
  72.                                 '</i>', '', None))
  73.  
  74.         def fill_language(self, piter, expand=True):
  75.                 # Remove all children
  76.                 child = self.model.iter_children(piter)
  77.                 
  78.                 while child and self.model.remove(child):
  79.                         True
  80.                 
  81.                 path = self.model.get_path(piter)
  82.                 nodes = self.get_language_snippets(path)
  83.                 language = self.get_language(path)
  84.                 
  85.                 Library().ref(language)
  86.                 
  87.                 if nodes:
  88.                         for node in nodes:
  89.                                 self.add_snippet(piter, node)
  90.                 else:
  91.                         # Add node that tells there are no snippets currently
  92.                         self.add_new_snippet_node(piter)
  93.  
  94.                 if expand:
  95.                         self.tree_view.expand_row(path, False)
  96.  
  97.         def build_model(self, force_reload = False):
  98.                 window = gedit.app_get_default().get_active_window()
  99.                 
  100.                 if window:
  101.                         view = window.get_active_view()
  102.  
  103.                         if not view:
  104.                                 current_lang = None
  105.                         else:
  106.                                 current_lang = view.get_buffer().get_language()
  107.                                 source_view = self['source_view_snippet']
  108.  
  109.                 else:
  110.                         current_lang = None
  111.  
  112.                 tree_view = self['tree_view_snippets']
  113.                 expand = None
  114.                 
  115.                 if not self.model or force_reload:
  116.                         self.model = gtk.TreeStore(str, str, object)
  117.                         self.model.set_sort_column_id(self.SORT_COLUMN, gtk.SORT_ASCENDING)
  118.                         manager = self.get_language_manager()
  119.                         langs = gedit.language_manager_list_languages_sorted(manager, True)
  120.                         
  121.                         piter = self.model.append(None, (_('Global'), '', None))
  122.                         # Add dummy node
  123.                         self.model.append(piter, ('', '', None))
  124.                         
  125.                         nm = None
  126.                         
  127.                         if current_lang:
  128.                                 nm = current_lang.get_name()
  129.                 
  130.                         for lang in langs:
  131.                                 name = lang.get_name()
  132.                                 parent = self.model.append(None, (name, name, lang))
  133.  
  134.                                 # Add dummy node
  135.                                 self.model.append(parent, ('', '', None))
  136.  
  137.                                 if (nm == name):
  138.                                         expand = parent
  139.                 else:
  140.                         if current_lang:
  141.                                 piter = self.model.get_iter_first()
  142.                                 nm = current_lang.get_name()
  143.                                 
  144.                                 while piter:
  145.                                         lang = self.model.get_value(piter, \
  146.                                                         self.SORT_COLUMN)
  147.                                         
  148.                                         if lang == nm:
  149.                                                 expand = piter
  150.                                                 break;
  151.                                                 
  152.                                         piter = self.model.iter_next(piter)
  153.  
  154.                 tree_view.set_model(self.model)
  155.                 
  156.                 if not expand:
  157.                         expand = self.model.get_iter_root()
  158.                         
  159.                 tree_view.expand_row(self.model.get_path(expand), False)
  160.                 self.select_iter(expand)
  161.  
  162.         def get_cell_data_pixbuf_cb(self, column, cell, model, iter):
  163.                 s = model.get_value(iter, self.OBJ_COLUMN)
  164.                 
  165.                 snippet = isinstance(s, SnippetData)
  166.                 
  167.                 if snippet and not s.valid:
  168.                         cell.set_property('stock-id', gtk.STOCK_DIALOG_ERROR)
  169.                 else:
  170.                         cell.set_property('stock-id', None)
  171.  
  172.                 cell.set_property('xalign', 1.0)
  173.                 
  174.         def get_cell_data_cb(self, column, cell, model, iter):
  175.                 s = model.get_value(iter, self.OBJ_COLUMN)
  176.                 
  177.                 snippet = isinstance(s, SnippetData)
  178.                 
  179.                 cell.set_property('editable', snippet)
  180.                 cell.set_property('markup', model.get_value(iter, self.NAME_COLUMN))
  181.  
  182.         def on_tree_view_drag_data_get(self, widget, context, selection_data, info, time):
  183.                 gfile = gio.File(self._temp_export)
  184.                 selection_data.set_uris([gfile.get_uri()])
  185.        
  186.         def on_tree_view_drag_begin(self, widget, context):
  187.                 self.dragging = True
  188.                 
  189.                 if self._temp_export:
  190.                       shutil.rmtree(os.path.dirname(self._temp_export))
  191.                       self._temp_export = None
  192.  
  193.                 if self.dnd_name:
  194.                         context.set_icon_name(self.dnd_name, 0, 0)
  195.  
  196.                 dirname = tempfile.mkdtemp()
  197.                 filename = os.path.join(dirname, self.default_export_name)
  198.                 
  199.                 # Generate temporary file name
  200.                 self.export_snippets(filename, False)
  201.                 self._temp_export = filename
  202.         
  203.         def on_tree_view_drag_end(self, widget, context):
  204.                 self.dragging = False
  205.  
  206.         def on_tree_view_drag_data_received(self, widget, context, x, y, selection, info, timestamp):
  207.                 uris = selection.get_uris()
  208.                 
  209.                 self.import_snippets(uris)
  210.  
  211.         def on_tree_view_drag_motion(self, widget, context, x, y, timestamp):
  212.                 # Return False if we are dragging
  213.                 if self.dragging:
  214.                         return False
  215.                 
  216.                 # Check uri target
  217.                 if not gtk.targets_include_uri(context.targets):
  218.                         return False
  219.  
  220.                 # Check action
  221.                 action = None
  222.                 if context.suggested_action == gdk.ACTION_COPY:
  223.                         action = gdk.ACTION_COPY
  224.                 else:
  225.                         for act in context.actions:
  226.                                 if act == gdk.ACTION_COPY:
  227.                                       action = gdk.ACTION_COPY
  228.                                       break  
  229.                 
  230.                 if action == gdk.ACTION_COPY:
  231.                         context.drag_status(gdk.ACTION_COPY, timestamp)        
  232.                         return True
  233.                 else:
  234.                         return False
  235.  
  236.         def build_dnd(self):
  237.                 tv = self.tree_view
  238.                 
  239.                 # Set it as a drag source for exporting snippets
  240.                 tv.drag_source_set(gdk.BUTTON1_MASK, self.dnd_target_list, gdk.ACTION_DEFAULT | gdk.ACTION_COPY)
  241.                 
  242.                 # Set it as a drag destination for importing snippets
  243.                 tv.drag_dest_set(gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP, 
  244.                                  self.dnd_target_list, gdk.ACTION_DEFAULT | gdk.ACTION_COPY)
  245.                 
  246.                 tv.connect('drag_data_get', self.on_tree_view_drag_data_get)
  247.                 tv.connect('drag_begin', self.on_tree_view_drag_begin)
  248.                 tv.connect('drag_end', self.on_tree_view_drag_end)
  249.                 tv.connect('drag_data_received', self.on_tree_view_drag_data_received)
  250.                 tv.connect('drag_motion', self.on_tree_view_drag_motion)
  251.  
  252.                 theme = gtk.icon_theme_get_for_screen(tv.get_screen())
  253.                 
  254.                 self.dnd_name = None
  255.                 for name in self.drag_icons:
  256.                         icon = theme.lookup_icon(name, gtk.ICON_SIZE_DND, 0)
  257.                         
  258.                         if icon:
  259.                                 self.dnd_name = name
  260.                                 break
  261.                 
  262.         def build_tree_view(self):                
  263.                 self.tree_view = self['tree_view_snippets']
  264.                 
  265.                 self.column = gtk.TreeViewColumn(None)
  266.  
  267.                 self.renderer = gtk.CellRendererText()
  268.                 self.column.pack_start(self.renderer, False)
  269.                 self.column.set_cell_data_func(self.renderer, self.get_cell_data_cb)
  270.  
  271.                 renderer = gtk.CellRendererPixbuf()
  272.                 self.column.pack_start(renderer, True)
  273.                 self.column.set_cell_data_func(renderer, self.get_cell_data_pixbuf_cb)
  274.  
  275.                 self.tree_view.append_column(self.column)
  276.                 
  277.                 self.renderer.connect('edited', self.on_cell_edited)
  278.                 self.renderer.connect('editing-started', self.on_cell_editing_started)
  279.  
  280.                 selection = self.tree_view.get_selection()
  281.                 selection.set_mode(gtk.SELECTION_MULTIPLE)
  282.                 selection.connect('changed', self.on_tree_view_selection_changed)
  283.                 
  284.                 self.build_dnd()
  285.         
  286.         def get_language_manager(self):
  287.                 if not self.manager:
  288.                         dirs = []
  289.                 
  290.                         for d in Library().systemdirs:
  291.                                 dirs.append(os.path.join(d, 'lang'))
  292.                 
  293.                         self.manager = gsv.LanguageManager()
  294.                         self.manager.set_search_path(dirs + self.manager.get_search_path())
  295.                 
  296.                 return self.manager
  297.                 
  298.         def build(self):
  299.                 self.builder = gtk.Builder()
  300.                 self.builder.add_from_file(os.path.join(self.datadir, 'ui', 'snippets.ui'))
  301.                 
  302.                 handlers_dic = {
  303.                         'on_dialog_snippets_response': self.on_dialog_snippets_response,
  304.                         'on_dialog_snippets_destroy': self.on_dialog_snippets_destroy,
  305.                         'on_button_new_snippet_clicked': self.on_button_new_snippet_clicked,
  306.                         'on_button_import_snippets_clicked': self.on_button_import_snippets_clicked,
  307.                         'on_button_export_snippets_clicked': self.on_button_export_snippets_clicked,
  308.                         'on_button_remove_snippet_clicked': self.on_button_remove_snippet_clicked,
  309.                         'on_entry_tab_trigger_focus_out': self.on_entry_tab_trigger_focus_out,
  310.                         'on_entry_tab_trigger_changed': self.on_entry_tab_trigger_changed,
  311.                         'on_entry_accelerator_focus_out': self.on_entry_accelerator_focus_out,
  312.                         'on_entry_accelerator_focus_in': self.on_entry_accelerator_focus_in,
  313.                         'on_entry_accelerator_key_press': self.on_entry_accelerator_key_press,
  314.                         'on_source_view_snippet_focus_out': self.on_source_view_snippet_focus_out,
  315.                         'on_tree_view_snippets_row_expanded': self.on_tree_view_snippets_row_expanded,
  316.                         'on_tree_view_snippets_key_press': self.on_tree_view_snippets_key_press}
  317.  
  318.                 self.builder.connect_signals(handlers_dic)
  319.                 
  320.                 self.build_tree_view()
  321.                 self.build_model()
  322.  
  323.                 image = self['image_remove']
  324.                 image.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_SMALL_TOOLBAR)
  325.  
  326.                 source_view = self['source_view_snippet']
  327.                 manager = self.get_language_manager()
  328.                 lang = manager.get_language('snippets')
  329.  
  330.                 if lang:
  331.                         source_view.get_buffer().set_highlight_syntax(True)
  332.                         source_view.get_buffer().set_language(lang)
  333.                         self.snippets_doc = Document(None, source_view)
  334.                                 
  335.                 entry = self['combo_drop_targets'].child
  336.                 entry.connect('focus-out-event', self.on_entry_drop_targets_focus_out)
  337.                 entry.connect('drag-data-received', self.on_entry_drop_targets_drag_data_received)
  338.                 
  339.                 lst = entry.drag_dest_get_target_list()
  340.                 lst = gtk.target_list_add_uri_targets(entry.drag_dest_get_target_list(), self.TARGET_URI)
  341.                 entry.drag_dest_set_target_list(lst)
  342.                 
  343.                 self.dlg = self['dialog_snippets']
  344.                 
  345.                 if self.default_size:
  346.                         self.dlg.set_default_size(*self.default_size)
  347.         
  348.         def __getitem__(self, key):
  349.                 return self.builder.get_object(key)
  350.  
  351.         def is_filled(self, piter):
  352.                 if not self.model.iter_has_child(piter):
  353.                         return True
  354.                 
  355.                 child = self.model.iter_children(piter)
  356.                 nm = self.model.get_value(child, self.NAME_COLUMN)
  357.                 obj = self.model.get_value(child, self.OBJ_COLUMN)
  358.                 
  359.                 return (obj or nm)
  360.  
  361.         def fill_if_needed(self, piter, expand=True):
  362.                 if not self.is_filled(piter):
  363.                         self.fill_language(piter, expand)
  364.  
  365.         def find_iter(self, parent, snippet):
  366.                 self.fill_if_needed(parent)
  367.                 piter = self.model.iter_children(parent)
  368.                 
  369.                 while (piter):
  370.                         node = self.model.get_value(piter, self.OBJ_COLUMN)
  371.  
  372.                         if node == snippet.data:
  373.                                 return piter
  374.                         
  375.                         piter = self.model.iter_next(piter)
  376.                 
  377.                 return None
  378.  
  379.         def selected_snippets_state(self):
  380.                 snippets = self.selected_snippets(False)
  381.                 override = False
  382.                 remove = False
  383.                 system = False
  384.                 
  385.                 for snippet in snippets:
  386.                         if not snippet:
  387.                                 continue
  388.  
  389.                         if snippet.is_override():
  390.                                 override = True
  391.                         elif snippet.can_modify():
  392.                                 remove = True
  393.                         else:
  394.                                 system = True
  395.                         
  396.                         # No need to continue if both are found
  397.                         if override and remove:
  398.                                 break
  399.  
  400.                 return (override, remove, system)
  401.  
  402.         def update_buttons(self):
  403.                 button_remove = self['button_remove_snippet']
  404.                 button_new = self['button_new_snippet']
  405.                 image_remove = self['image_remove']
  406.  
  407.                 button_new.set_sensitive(self.language_path != None)
  408.                 override, remove, system = self.selected_snippets_state()
  409.                 
  410.                 if not (override ^ remove) or system:
  411.                         button_remove.set_sensitive(False)
  412.                         image_remove.set_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_BUTTON)
  413.                 else:
  414.                         button_remove.set_sensitive(True)
  415.                         
  416.                         if override:
  417.                                 image_remove.set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_BUTTON)
  418.                                 tooltip = _('Revert selected snippet')
  419.                         else:
  420.                                 image_remove.set_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_BUTTON)
  421.                                 tooltip = _('Delete selected snippet')
  422.                         
  423.                         self.tooltips.set_tip(button_remove, tooltip)
  424.  
  425.         def snippet_changed(self, piter = None):
  426.                 if piter:
  427.                         node = self.model.get_value(piter, self.OBJ_COLUMN)
  428.                         s = Snippet(node)
  429.                 else:
  430.                         s = self.snippet
  431.                         piter = self.find_iter(self.model.get_iter(self.language_path), s)
  432.  
  433.                 if piter:
  434.                         nm = s.display()
  435.                         
  436.                         self.model.set(piter, self.NAME_COLUMN, nm, self.SORT_COLUMN, nm)
  437.                         self.update_buttons()
  438.                         self.entry_tab_trigger_update_valid()
  439.  
  440.                 return piter
  441.  
  442.         def add_snippet(self, parent, snippet):
  443.                 piter = self.model.append(parent, ('', '', snippet))
  444.                 
  445.                 return self.snippet_changed(piter)
  446.  
  447.         def run(self):
  448.                 if not self.dlg:
  449.                         self.build()
  450.                         self.dlg.show()
  451.                 else:
  452.                         self.build_model()
  453.                         self.dlg.present()
  454.  
  455.         
  456.         def snippet_from_iter(self, model, piter):
  457.                 parent = model.iter_parent(piter)
  458.                 
  459.                 if parent:
  460.                         return model.get_value(piter, self.OBJ_COLUMN)
  461.                 else:
  462.                         return None
  463.         
  464.         def language_snippets(self, model, parent, as_path=False):
  465.                 self.fill_if_needed(parent, False)
  466.                 piter = model.iter_children(parent)
  467.                 snippets = []
  468.                 
  469.                 if not piter:
  470.                         return snippets
  471.                 
  472.                 while piter:
  473.                         snippet = self.snippet_from_iter(model, piter)
  474.                         
  475.                         if snippet:
  476.                                 if as_path:
  477.                                         snippets.append(model.get_path(piter))
  478.                                 else:
  479.                                         snippets.append(snippet)
  480.  
  481.                         piter = model.iter_next(piter)
  482.                 
  483.                 return snippets
  484.         
  485.         def selected_snippets(self, include_languages=True, as_path=False):
  486.                 selection = self.tree_view.get_selection()
  487.                 (model, paths) = selection.get_selected_rows()
  488.                 snippets = []
  489.                 
  490.                 if paths and len(paths) != 0:
  491.                         for p in paths:
  492.                                 piter = model.get_iter(p)
  493.                                 parent = model.iter_parent(piter)
  494.                                 
  495.                                 if not piter:
  496.                                         continue
  497.                                 
  498.                                 if parent:
  499.                                         snippet = self.snippet_from_iter(model, piter)
  500.                                         
  501.                                         if not snippet:
  502.                                                 continue
  503.                                         
  504.                                         if as_path:
  505.                                                 snippets.append(p)
  506.                                         else:
  507.                                                 snippets.append(snippet)
  508.                                 elif include_languages:
  509.                                         snippets += self.language_snippets(model, piter, as_path)
  510.                         
  511.                 return snippets                        
  512.         
  513.         def selected_snippet(self):
  514.                 selection = self.tree_view.get_selection()
  515.                 (model, paths) = selection.get_selected_rows()
  516.                 
  517.                 if len(paths) == 1:
  518.                         piter = model.get_iter(paths[0])
  519.                         parent = model.iter_parent(piter)
  520.                         snippet = self.snippet_from_iter(model, piter)
  521.                         
  522.                         return parent, piter, snippet
  523.                 else:
  524.                         return None, None, None
  525.  
  526.         def selection_changed(self):
  527.                 if not self.snippet:
  528.                         sens = False
  529.  
  530.                         self['entry_tab_trigger'].set_text('')
  531.                         self['entry_accelerator'].set_text('')                        
  532.                         self['source_view_snippet'].get_buffer().set_text('')
  533.                         self['combo_drop_targets'].child.set_text('')
  534.  
  535.                         self.tooltips.disable()
  536.                 else:
  537.                         sens = True
  538.  
  539.                         self['entry_tab_trigger'].set_text(self.snippet['tag'])
  540.                         self['entry_accelerator'].set_text( \
  541.                                         self.snippet.accelerator_display())
  542.                         self['combo_drop_targets'].child.set_text(', '.join(self.snippet['drop-targets']))
  543.                         
  544.                         buf = self['source_view_snippet'].get_buffer()
  545.                         buf.set_text(self.snippet['text'])
  546.                         
  547.                         self.tooltips.enable()
  548.  
  549.                 for name in ['source_view_snippet', 'label_tab_trigger',
  550.                                 'entry_tab_trigger', 'label_accelerator', 
  551.                                 'entry_accelerator', 'label_drop_targets',
  552.                                 'combo_drop_targets']:
  553.                         self[name].set_sensitive(sens)
  554.                 
  555.                 self.update_buttons()
  556.                         
  557.         def select_iter(self, piter, unselect=True):
  558.                 selection = self.tree_view.get_selection()
  559.                 
  560.                 if unselect:
  561.                         selection.unselect_all()
  562.  
  563.                 selection.select_iter(piter)
  564.                 
  565.                 self.tree_view.scroll_to_cell(self.model.get_path(piter), None, \
  566.                         True, 0.5, 0.5)
  567.  
  568.         def get_language(self, path):
  569.                 if path[0] == 0:
  570.                         return None
  571.                 else:
  572.                         return self.model.get_value(self.model.get_iter( \
  573.                                         (path[0],)), self.OBJ_COLUMN).get_id()
  574.  
  575.         def new_snippet(self, properties=None):
  576.                 if not self.language_path:
  577.                         return None
  578.  
  579.                 snippet = Library().new_snippet(self.get_language(self.language_path), properties)
  580.                 
  581.                 return Snippet(snippet)
  582.  
  583.         def get_dummy(self, parent):
  584.                 if not self.model.iter_n_children(parent) == 1:
  585.                         return None
  586.                 
  587.                 dummy = self.model.iter_children(parent)
  588.                 
  589.                 if not self.model.get_value(dummy, self.OBJ_COLUMN):
  590.                         return dummy
  591.         
  592.                 return None
  593.         
  594.         def unref_languages(self):
  595.                 piter = self.model.get_iter_first()
  596.                 library = Library()
  597.                 
  598.                 while piter:
  599.                         if self.is_filled(piter):
  600.                                 language = self.get_language(self.model.get_path(piter))
  601.                                 library.save(language)
  602.  
  603.                                 library.unref(language)
  604.                         
  605.                         piter = self.model.iter_next(piter)
  606.  
  607.         # Callbacks
  608.         def on_dialog_snippets_destroy(self, dlg):
  609.                 # Remove temporary drag export
  610.                 if self._temp_export:
  611.                       shutil.rmtree(os.path.dirname(self._temp_export))
  612.                       self._temp_export = None
  613.  
  614.                 if self.snippets_doc:
  615.                         self.snippets_doc.stop()
  616.                 
  617.                 self.default_size = [dlg.allocation.width, dlg.allocation.height]
  618.                 self.manager = None
  619.  
  620.                 self.unref_languages()        
  621.                 self.snippet = None        
  622.                 self.model = None
  623.                 self.dlg = None                
  624.         
  625.         def on_dialog_snippets_response(self, dlg, resp):                                
  626.                 if resp == gtk.RESPONSE_HELP:
  627.                         gedit.help_display(self.dlg, 'gedit', 'gedit-snippets-plugin')
  628.                         return
  629.  
  630.                 self.dlg.destroy()
  631.         
  632.         def on_cell_editing_started(self, renderer, editable, path):
  633.                 piter = self.model.get_iter(path)
  634.                 
  635.                 if not self.model.iter_parent(piter):
  636.                         renderer.stop_editing(True)
  637.                         editable.remove_widget()
  638.                 elif isinstance(editable, gtk.Entry):
  639.                         if self.snippet:
  640.                                 editable.set_text(self.snippet['description'])
  641.                         else:
  642.                                 # This is the `Add a new snippet...` item
  643.                                 editable.set_text('')
  644.                         
  645.                         editable.grab_focus()
  646.         
  647.         def on_cell_edited(self, cell, path, new_text):                
  648.                 if new_text != '':
  649.                         piter = self.model.get_iter(path)
  650.                         node = self.model.get_value(piter, self.OBJ_COLUMN)
  651.                         
  652.                         if node:
  653.                                 if node == self.snippet.data:
  654.                                         s = self.snippet
  655.                                 else:
  656.                                         s = Snippet(node)
  657.                         
  658.                                 s['description'] = new_text
  659.                                 self.snippet_changed(piter)
  660.                                 self.select_iter(piter)
  661.                         else:
  662.                                 # This is the `Add a new snippet...` item
  663.                                 # We create a new snippet
  664.                                 snippet = self.new_snippet({'description': new_text})
  665.                                 
  666.                                 if snippet:
  667.                                         self.model.set(piter, self.OBJ_COLUMN, snippet.data)
  668.                                         self.snippet_changed(piter)
  669.                                         self.snippet = snippet
  670.                                         self.selection_changed()
  671.         
  672.         def on_entry_accelerator_focus_out(self, entry, event):
  673.                 if not self.snippet:
  674.                         return
  675.  
  676.                 entry.set_text(self.snippet.accelerator_display())
  677.  
  678.         def entry_tab_trigger_update_valid(self):
  679.                 entry = self['entry_tab_trigger']
  680.                 text = entry.get_text()
  681.                 
  682.                 if text and not Library().valid_tab_trigger(text):
  683.                         img = self['image_tab_trigger']
  684.                         img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_BUTTON)
  685.                         img.show()
  686.  
  687.                         #self['hbox_tab_trigger'].set_spacing(3)
  688.                         tip = _('This is not a valid tab trigger. Triggers can either contain letters or a single, non alphanumeric, character like {, [, etcetera.')
  689.                         
  690.                         self.tooltips.set_tip(entry, tip)
  691.                         self.tooltips.set_tip(img, tip)
  692.                 else:
  693.                         self['image_tab_trigger'].hide()
  694.                         #self['hbox_tab_trigger'].set_spacing(0)
  695.                         self.tooltips.set_tip(entry, _('Single word with which the snippet is activated after pressing tab'))
  696.                 
  697.                 return False
  698.  
  699.         def on_entry_tab_trigger_focus_out(self, entry, event):
  700.                 if not self.snippet:
  701.                         return
  702.  
  703.                 text = entry.get_text()
  704.  
  705.                 # save tag
  706.                 self.snippet['tag'] = text
  707.                 self.snippet_changed()
  708.         
  709.         def on_entry_drop_targets_focus_out(self, entry, event):
  710.                 if not self.snippet:
  711.                         return
  712.                 
  713.                 text = entry.get_text()
  714.  
  715.                 # save drop targets
  716.                 self.snippet['drop-targets'] = text
  717.                 self.snippet_changed()
  718.         
  719.         def on_entry_tab_trigger_changed(self, entry):
  720.                 self.entry_tab_trigger_update_valid()
  721.         
  722.         def on_source_view_snippet_focus_out(self, source_view, event):
  723.                 if not self.snippet:
  724.                         return
  725.  
  726.                 buf = source_view.get_buffer()
  727.                 text = buf.get_text(buf.get_start_iter(), \
  728.                                 buf.get_end_iter())
  729.  
  730.                 self.snippet['text'] = text
  731.                 self.snippet_changed()
  732.         
  733.         def on_button_new_snippet_clicked(self, button):
  734.                 snippet = self.new_snippet()
  735.                 
  736.                 if not snippet:
  737.                         return
  738.  
  739.                 parent = self.model.get_iter(self.language_path)
  740.                 path = self.model.get_path(parent)
  741.                 
  742.                 dummy = self.get_dummy(parent)
  743.                 
  744.                 if dummy:
  745.                         # Remove the dummy
  746.                         self.model.remove(dummy)
  747.                 
  748.                 # Add the snippet
  749.                 piter = self.add_snippet(parent, snippet.data)
  750.                 self.select_iter(piter)
  751.  
  752.                 if not self.tree_view.row_expanded(path):
  753.                         self.tree_view.expand_row(path, False)
  754.                         self.select_iter(piter)
  755.  
  756.                 self.tree_view.grab_focus()
  757.  
  758.                 path = self.model.get_path(piter)
  759.                 self.tree_view.set_cursor(path, self.column, True)
  760.         
  761.         def file_filter(self, name, pattern):
  762.                 fil = gtk.FileFilter()
  763.                 fil.set_name(name)
  764.                 
  765.                 for p in pattern:
  766.                         fil.add_pattern(p)
  767.                 
  768.                 return fil
  769.         
  770.         def import_snippets(self, filenames):
  771.                 success = True
  772.                 
  773.                 for filename in filenames:
  774.                         if not gedit.utils.uri_has_file_scheme(filename):
  775.                                 continue
  776.  
  777.                         # Remove file://
  778.                         gfile = gio.File(filename)
  779.                         filename = gfile.get_path()
  780.  
  781.                         importer = Importer(filename)
  782.                         error = importer.run()
  783.          
  784.                         if error:
  785.                                 message = _('The following error occurred while importing: %s') % error
  786.                                 success = False
  787.                                 message_dialog(self.dlg, gtk.MESSAGE_ERROR, message)
  788.                 
  789.                 self.build_model(True)
  790.  
  791.                 if success:
  792.                         message = _('Import successfully completed')
  793.                         message_dialog(self.dlg, gtk.MESSAGE_INFO, message)
  794.                
  795.         def on_import_response(self, dialog, response):
  796.                 if response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_CLOSE:
  797.                         dialog.destroy()
  798.                         return
  799.                 
  800.                 f = dialog.get_uris()
  801.                 dialog.destroy()
  802.                 
  803.                 self.import_snippets(f)
  804.                 
  805.         def on_button_import_snippets_clicked(self, button):
  806.                 dlg = gtk.FileChooserDialog(parent=self.dlg, title=_("Import snippets"), 
  807.                                 action=gtk.FILE_CHOOSER_ACTION_OPEN, 
  808.                                 buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
  809.                                          gtk.STOCK_OPEN, gtk.RESPONSE_OK))
  810.                 
  811.                 dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar', '*.xml')))
  812.                 dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
  813.                 dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
  814.                 dlg.add_filter(self.file_filter(_('Single snippets file'), ('*.xml',)))
  815.                 dlg.add_filter(self.file_filter(_('All files'), '*'))
  816.  
  817.                 dlg.connect('response', self.on_import_response)
  818.                 dlg.set_local_only(True)
  819.                 
  820.                 dlg.show()
  821.  
  822.         def export_snippets_real(self, filename, snippets, show_dialogs=True):
  823.                 export = Exporter(filename, snippets)
  824.                 error = export.run()
  825.                 
  826.                 if error:
  827.                         message = _('The following error occurred while exporting: %s') % error
  828.                         msgtype = gtk.MESSAGE_ERROR
  829.                         retval = False
  830.                 else:
  831.                         message = _('Export successfully completed')
  832.                         msgtype = gtk.MESSAGE_INFO
  833.                         retval = True
  834.  
  835.                 if show_dialogs:
  836.                         message_dialog(self.dlg, msgtype, message)
  837.  
  838.                 return retval
  839.                 
  840.         def on_export_response(self, dialog, response):
  841.                 filename = dialog.get_filename()
  842.                 snippets = dialog._export_snippets
  843.                 
  844.                 dialog.destroy()
  845.                 
  846.                 if response != gtk.RESPONSE_OK:
  847.                         return
  848.                 
  849.                 self.export_snippets_real(filename, snippets);
  850.         
  851.         def export_snippets(self, filename=None, show_dialogs=True):
  852.                 snippets = self.selected_snippets()
  853.                 
  854.                 if not snippets or len(snippets) == 0:
  855.                         return False
  856.                         
  857.                 usersnippets = []
  858.                 systemsnippets = []
  859.  
  860.                 # Iterate through snippets and look for system snippets
  861.                 for snippet in snippets:
  862.                         if snippet.can_modify():
  863.                                 usersnippets.append(snippet)
  864.                         else:
  865.                                 systemsnippets.append(snippet)
  866.                
  867.                 export_snippets = snippets
  868.  
  869.                 if len(systemsnippets) != 0 and show_dialogs:
  870.                         # Ask if system snippets should also be exported
  871.                         message = _('Do you want to include selected <b>system</b> snippets in your export?')
  872.                         mes = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, 
  873.                                         type=gtk.MESSAGE_QUESTION, 
  874.                                         buttons=gtk.BUTTONS_YES_NO,
  875.                                         message_format=message)
  876.                         mes.set_property('use-markup', True)
  877.                         resp = mes.run()
  878.                         mes.destroy()
  879.                         
  880.                         if resp == gtk.RESPONSE_NO:
  881.                                 export_snippets = usersnippets
  882.                         elif resp != gtk.RESPONSE_YES:
  883.                                 return False
  884.                 
  885.                 if len(export_snippets) == 0 and show_dialogs:                        
  886.                         message = _('There are no snippets selected to be exported')
  887.                         message_dialog(self.dlg, gtk.MESSAGE_INFORMATION, message)
  888.                         return False
  889.                 
  890.                 if not filename:
  891.                         dlg = gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'), 
  892.                                         action=gtk.FILE_CHOOSER_ACTION_SAVE, 
  893.                                         buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
  894.                                                  gtk.STOCK_SAVE, gtk.RESPONSE_OK))
  895.                         
  896.                         dlg._export_snippets = export_snippets
  897.                         dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar')))
  898.                         dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
  899.                         dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
  900.  
  901.                         dlg.add_filter(self.file_filter(_('All files'), '*'))
  902.                         dlg.set_do_overwrite_confirmation(True)
  903.                         dlg.set_current_name(self.default_export_name)
  904.                 
  905.                         dlg.connect('response', self.on_export_response)
  906.                         dlg.set_local_only(True)
  907.                 
  908.                         dlg.show()
  909.                         return True
  910.                 else:
  911.                         return self.export_snippets_real(filename, export_snippets, show_dialogs)
  912.         
  913.         def on_button_export_snippets_clicked(self, button):
  914.                 snippets = self.selected_snippets()
  915.                 
  916.                 if not snippets or len(snippets) == 0:
  917.                         return
  918.                         
  919.                 usersnippets = []
  920.                 systemsnippets = []
  921.  
  922.                 # Iterate through snippets and look for system snippets
  923.                 for snippet in snippets:
  924.                         if snippet.can_modify():
  925.                                 usersnippets.append(snippet)
  926.                         else:
  927.                                 systemsnippets.append(snippet)
  928.  
  929.                 dlg = gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'), 
  930.                                 action=gtk.FILE_CHOOSER_ACTION_SAVE, 
  931.                                 buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
  932.                                          gtk.STOCK_SAVE, gtk.RESPONSE_OK))
  933.                 
  934.                 dlg._export_snippets = snippets
  935.  
  936.                 if len(systemsnippets) != 0:
  937.                         # Ask if system snippets should also be exported
  938.                         message = _('Do you want to include selected <b>system</b> snippets in your export?')
  939.                         mes = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, 
  940.                                         type=gtk.MESSAGE_QUESTION, 
  941.                                         buttons=gtk.BUTTONS_YES_NO,
  942.                                         message_format=message)
  943.                         mes.set_property('use-markup', True)
  944.                         resp = mes.run()
  945.                         mes.destroy()
  946.                         
  947.                         if resp == gtk.RESPONSE_NO:
  948.                                 dlg._export_snippets = usersnippets
  949.                         elif resp != gtk.RESPONSE_YES:
  950.                                 dlg.destroy()
  951.                                 return
  952.                 
  953.                 if len(dlg._export_snippets) == 0:
  954.                         dlg.destroy()
  955.                         
  956.                         message = _('There are no snippets selected to be exported')
  957.                         message_dialog(self.dlg, gtk.MESSAGE_INFORMATION, message)
  958.                         return
  959.                 
  960.                 dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar')))
  961.                 dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
  962.                 dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
  963.  
  964.                 dlg.add_filter(self.file_filter(_('All files'), '*'))
  965.                 dlg.set_do_overwrite_confirmation(True)
  966.                 dlg.set_current_name(self.default_export_name)
  967.                 
  968.                 dlg.connect('response', self.on_export_response)
  969.                 dlg.set_local_only(True)
  970.                 
  971.                 dlg.show()                
  972.         
  973.         def remove_snippet_revert(self, path, piter):
  974.                 node = self.snippet_from_iter(self.model, piter)
  975.                 Library().revert_snippet(node)
  976.                 
  977.                 return piter
  978.         
  979.         def remove_snippet_delete(self, path, piter):
  980.                 node = self.snippet_from_iter(self.model, piter)
  981.                 parent = self.model.iter_parent(piter)
  982.  
  983.                 Library().remove_snippet(node)
  984.  
  985.                 if self.model.remove(piter):
  986.                         return piter
  987.                 elif path[-1] != 0:
  988.                         self.select_iter(self.model.get_iter((path[0], path[1] - 1)))
  989.                 else:
  990.                         dummy = self.add_new_snippet_node(parent)
  991.                         self.tree_view.expand_row(self.model.get_path(parent), False)
  992.                         return dummy
  993.        
  994.         def on_button_remove_snippet_clicked(self, button):
  995.                 override, remove, system = self.selected_snippets_state()
  996.                 
  997.                 if not (override ^ remove) or system:
  998.                         return
  999.                 
  1000.                 paths = self.selected_snippets(include_languages=False, as_path=True)
  1001.                 
  1002.                 if override:
  1003.                         action = self.remove_snippet_revert
  1004.                 else:
  1005.                         action = self.remove_snippet_delete
  1006.                 
  1007.                 # Remove selection
  1008.                 self.tree_view.get_selection().unselect_all()
  1009.                 
  1010.                 # Create tree row references
  1011.                 references = []
  1012.                 for path in paths:
  1013.                         references.append(gtk.TreeRowReference(self.model, path))
  1014.  
  1015.                 # Remove/revert snippets
  1016.                 select = None
  1017.                 for reference in references:
  1018.                         path = reference.get_path()
  1019.                         piter = self.model.get_iter(path)
  1020.                         
  1021.                         res = action(path, piter)
  1022.                         
  1023.                         if res:
  1024.                                 select = res
  1025.  
  1026.                 if select:
  1027.                         self.select_iter(select)
  1028.  
  1029.                 self.selection_changed()
  1030.         
  1031.         def set_accelerator(self, keyval, mod):
  1032.                 accelerator = gtk.accelerator_name(keyval, mod)
  1033.                 self.snippet['accelerator'] = accelerator
  1034.  
  1035.                 return True
  1036.         
  1037.         def on_entry_accelerator_key_press(self, entry, event):
  1038.                 source_view = self['source_view_snippet']
  1039.  
  1040.                 if event.keyval == gdk.keyval_from_name('Escape'):
  1041.                         # Reset
  1042.                         entry.set_text(self.snippet.accelerator_display())
  1043.                         self.tree_view.grab_focus()
  1044.                         
  1045.                         return True
  1046.                 elif event.keyval == gdk.keyval_from_name('Delete') or \
  1047.                                 event.keyval == gdk.keyval_from_name('BackSpace'):
  1048.                         # Remove the accelerator
  1049.                         entry.set_text('')
  1050.                         self.snippet['accelerator'] = ''
  1051.                         self.tree_view.grab_focus()
  1052.                         
  1053.                         self.snippet_changed()
  1054.                         return True
  1055.                 elif Library().valid_accelerator(event.keyval, event.state):
  1056.                         # New accelerator
  1057.                         self.set_accelerator(event.keyval, \
  1058.                                         event.state & gtk.accelerator_get_default_mod_mask())
  1059.                         entry.set_text(self.snippet.accelerator_display())
  1060.                         self.snippet_changed()
  1061.                         self.tree_view.grab_focus()
  1062.  
  1063.                 else:
  1064.                         return True
  1065.         
  1066.         def on_entry_accelerator_focus_in(self, entry, event):
  1067.                 if self.snippet['accelerator']:
  1068.                         entry.set_text(_('Type a new shortcut, or press Backspace to clear'))
  1069.                 else:
  1070.                         entry.set_text(_('Type a new shortcut'))
  1071.         
  1072.         def update_language_path(self):
  1073.                 model, paths = self.tree_view.get_selection().get_selected_rows()
  1074.                 
  1075.                 # Check if all have the same language parent
  1076.                 current_parent = None
  1077.  
  1078.                 for path in paths:
  1079.                         piter = model.get_iter(path)
  1080.                         parent = model.iter_parent(piter)
  1081.                         
  1082.                         if parent:
  1083.                                 path = model.get_path(parent)
  1084.  
  1085.                         if current_parent != None and current_parent != path:
  1086.                                 current_parent = None
  1087.                                 break
  1088.                         else:
  1089.                                 current_parent = path
  1090.  
  1091.                 self.language_path = current_parent
  1092.                 
  1093.         def on_tree_view_selection_changed(self, selection):
  1094.                 parent, piter, node = self.selected_snippet()
  1095.                 
  1096.                 if self.snippet:
  1097.                         self.on_entry_tab_trigger_focus_out(self['entry_tab_trigger'],
  1098.                                         None)
  1099.                         self.on_source_view_snippet_focus_out(self['source_view_snippet'], 
  1100.                                         None)
  1101.                         self.on_entry_drop_targets_focus_out(self['combo_drop_targets'].child,
  1102.                                         None)
  1103.                 
  1104.                 self.update_language_path()
  1105.  
  1106.                 if node:
  1107.                         self.snippet = Snippet(node)
  1108.                 else:
  1109.                         self.snippet = None
  1110.  
  1111.                 self.selection_changed()
  1112.  
  1113.         def iter_after(self, target, after):
  1114.                 if not after:
  1115.                         return True
  1116.  
  1117.                 tp = self.model.get_path(target)
  1118.                 ap = self.model.get_path(after)
  1119.                 
  1120.                 if tp[0] > ap[0] or (tp[0] == ap[0] and (len(ap) == 1 or tp[1] > ap[1])):
  1121.                         return True
  1122.                 
  1123.                 return False
  1124.                 
  1125.         def on_tree_view_snippets_key_press(self, treeview, event):
  1126.                 if event.keyval == gdk.keyval_from_name('Delete'):
  1127.                         self.on_button_remove_snippet_clicked(None)
  1128.                         return True
  1129.  
  1130.         def on_tree_view_snippets_row_expanded(self, treeview, piter, path):
  1131.                 # Check if it is already filled
  1132.                 self.fill_if_needed(piter)
  1133.                 self.select_iter(piter)
  1134.         
  1135.         def on_entry_drop_targets_drag_data_received(self, entry, context, x, y, selection_data, info, timestamp):
  1136.                 if not gtk.targets_include_uri(context.targets):
  1137.                         return
  1138.                 
  1139.                 uris = drop_get_uris(selection_data)
  1140.                 
  1141.                 if not uris:
  1142.                         return
  1143.                 
  1144.                 if entry.get_text():
  1145.                         mimes = [entry.get_text()]
  1146.                 else:
  1147.                         mimes = []
  1148.                 
  1149.                 for uri in uris:
  1150.                         try:
  1151.                                 mime = gio.content_type_guess(uri)
  1152.                         except:
  1153.                                 mime = None
  1154.                         
  1155.                         if mime:
  1156.                                 mimes.append(mime)
  1157.                 
  1158.                 entry.set_text(', '.join(mimes))
  1159.                 self.on_entry_drop_targets_focus_out(entry, None)
  1160.                 context.finish(True, False, timestamp)
  1161.                 
  1162.                 entry.stop_emission('drag_data_received')
  1163. # ex:ts=8:et:
  1164.